<?php

namespace Gnway\Ticket\Rest\Request;

class FrontHttpRequest
{

  /**
   * Origin input stream.
   *
   * @var array|null
   */
  protected ?array $_raw_input_stream = NULL;

  /**
   * Fetch from get.
   *
   * @param null $index
   * @return array|mixed|null
   */
  public function get($index = NULL)
  {
    return $this->_fetch_from_array($_GET, $index);
  }

  /**
   * Fetch from post.
   *
   * @param null $index
   * @return array|mixed|null
   */
  public function post($index = NULL)
  {
    return $this->_fetch_from_array($_POST, $index);
  }

  /**
   * Fetch parameter auto.
   *
   * @param null $index
   * @return array|mixed|null
   */
  public function getParameter($index = NULL)
  {
    switch (strtolower($this->server('REQUEST_METHOD'))) {
      case 'get':
        $data = $this->get($index);
        break;
      case 'post':
        $data = $this->post($index);
        break;
      default:
        $data = $this->stream($index);
    }

    return $data;
  }

  /**
   * Fetch from server.
   *
   * @param null $index
   * @return array|mixed|null
   */
  public function server($index = NULL)
  {
    return $this->_fetch_from_array($_SERVER, $index);
  }

  /**
   * Fetch from cookie.
   *
   * @param null $index
   * @return array|mixed|null
   */
  public function cookie($index = NULL)
  {
    return $this->_fetch_from_array($_COOKIE, $index);
  }

  /**
   * Fetch origin input stream.
   *
   * @param null $index
   * @return mixed
   */
  public function stream($index = NULL)
  {
    if ( ! is_array($this->_raw_input_stream)) {
      $raw_input_stream = (string)file_get_contents('php://input');
      if ($raw_input_stream[0] == '{') {
        $this->_raw_input_stream = json_decode($raw_input_stream, TRUE, 521, JSON_BIGINT_AS_STRING);
      }
      else {
        parse_str($raw_input_stream, $this->_raw_input_stream);
      }
      is_array($this->_raw_input_stream) OR $this->_raw_input_stream = [];
    }

    return $this->_fetch_from_array($this->_raw_input_stream, $index);
  }

  /**
   * Fetch argv.
   *
   * @return array
   */
  public function argv(): array
  {
    return array_slice($this->server('argv'), 1) ?? [];
  }

  /**
   * Check current requested is Ajax.
   *
   * @return bool
   */
  public function isAjax(): bool
  {
    return strtolower($this->server('HTTP_X_REQUESTED_WITH')) === 'xmlhttprequest';
  }

  /**
   * Check requested method.
   *
   * @param string $method
   * @return bool
   */
  public function isMethod(string $method = ''): bool
  {
    return $method && strtolower($this->server('REQUEST_METHOD')) === strtolower($method);
  }

  /**
   * Current run env is CLI.
   *
   * @return bool
   */
  public static function isCLI(): bool
  {
    return PHP_SAPI === 'cli' || defined('STDIN');
  }

  /**
   * Fetch from array.
   *
   * @param array &$array $_GET, $_POST, $_COOKIE, $_SERVER
   * @param array|string|null $index
   * @return array|mixed|null
   */
  protected function _fetch_from_array(array &$array, $index = NULL)
  {
    // If $index is NULL, it means that the whole $array is requested
    isset($index) OR $index = array_keys($array);

    // allow fetching multiple keys at once
    if (is_array($index)) {
      $output = [];
      foreach ($index as $key) {
        $output[$key] = $this->_fetch_from_array($array, $key);
      }

      return $output;
    }

    if (isset($array[$index])) {
      $value = $array[$index];
    } elseif (($count = preg_match_all('/(?:^[^\[]+)|\[[^]]*\]/', $index, $matches)) > 1) // Does the index contain array notation
    {
      $value = $array;
      for ($i = 0; $i < $count; $i++) {
        $key = trim($matches[0][$i], '[]');
        if ($key === '') // Empty notation will return the value as array
        {
          break;
        }

        if (isset($value[$key])) {
          $value = $value[$key];
        } else {
          return NULL;
        }
      }
    } else {
      return NULL;
    }

    return $value;
  }
}